import type { MessageData, Result } from "@/types";
import { eventBus, storage } from "@/utils";
import { Api } from "./Api";

const messages: Record<number, string> = {
	400: "发出的请求有错误，服务器没有进行新建或修改数据的操作。",
	401: "用户没有权限（令牌、用户名、密码错误）。",
	403: "用户得到授权，但是访问是被禁止的。",
	404: "发出的请求针对的是不存在的记录，服务器没有进行操作。",
	406: "请求的格式不可得。",
	410: "请求的资源被永久删除，且不会再得到的。",
	415: "请求方法或参数错误。",
	422: "当创建一个对象时，发生一个验证错误。",
	500: "服务器发生错误，请检查服务器。",
	502: "网关错误。",
	503: "服务不可用，服务器暂时过载或维护。",
	504: "网关超时。",
};

const api = new Api({
	baseUrl: "",
	customFetch: async (
		input: string | URL | globalThis.Request,
		init?: RequestInit,
	) => {
		let requestInit = init;
		if (!requestInit) {
			requestInit = {};
		}
		const claims = storage.getClaims();
		const headers: Record<string, string> = {
			Accept: "application/json",
		};
		if (claims) {
			headers.Authorization = `Bearer ${claims.token}`;
		}
		requestInit.headers = { ...requestInit.headers, ...headers };

		const response = await fetch(input, requestInit);
		if (!response.ok) {
			const msg = messages[response.status];
			if (msg) {
				publishMessage(msg, "notification", "error");
			}
			switch (response.status) {
				case 401: {
					storage.removeClaims();
					location.href = `/login?returnUrl=${encodeURIComponent(location.pathname)}`;
					break;
				}
			}
			throw new Error(msg);
		}
		if (response.status !== 200) {
			return response;
		}
		const data = await response.clone().json();
		if (data.success === undefined) {
			return response;
		}

		const { success, model, errCode, msg } = data as Result<unknown>;
		if (success) {
			response.json = () => Promise.resolve(model);
			return response;
		}
		if (errCode === "500" || errCode === "") {
			publishMessage(msg);
			throw new Error(msg);
		}
		return response;
	},
});

function publishMessage(
	msg: string,
	type: "notification" | "message" = "message",
	level: "error" | "warning" | "info" = "error",
) {
	eventBus.publish<MessageData>("message", {
		type,
		level,
		content: msg,
	});
}

export default api;

export * from "./data-contracts";
export * from "./http-client";
